package com.linx.common.core.utils;


import cn.hutool.core.util.ObjectUtil;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.linx.common.core.domain.dto.QrCodeInfoDTO;
import jakarta.servlet.http.HttpServletResponse;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/***
 * @ClassName QrCodeUtils
 * @Description TODO
 * @Author gushaoliang
 * @Date 2024/10/24 15:12
 * @Version 1.0
 */
/**
 * 二维码相关 工具类
 * <p>
 *
 * @since 2023/5/10 13:09
 */
public class QrCodeUtils {

    /**
     * 二维码宽和高
     */
    private static final int WIDTH_AND_HEIGHT = 400;
    /**
     * 文字的X轴坐标
     */
    private static final int TEXT_X = 180;
    /**
     * 文字的Y轴坐标
     */
    private static final int TEXT_Y = 80;

    /**
     * 二维码参数设置
     */
    private static final Map<EncodeHintType, Object> HINTS;

    static {
        HINTS = new EnumMap<>(EncodeHintType.class);
        //设置编码
        HINTS.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        //设置二维码的纠错级别
        HINTS.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
    }

    /**
     * 绘制二维码并返回图片流
     *
     * @param qrcode: 二维码值
     * @date 2022/4/8 14:44
     * @author YD
     */
    public static QrCodeInfoDTO createQrCode(String qrcode) {
        try {
            //设置对象并生成二维码
            BitMatrix bitMatrix = new MultiFormatWriter().encode(qrcode, BarcodeFormat.QR_CODE, WIDTH_AND_HEIGHT, WIDTH_AND_HEIGHT, HINTS);
            //创建二维码图片缓冲区
            BufferedImage image = new BufferedImage(WIDTH_AND_HEIGHT, WIDTH_AND_HEIGHT, BufferedImage.TYPE_INT_RGB);
            //生成二维码数组
            for (int x = 0; x < bitMatrix.getWidth(); x++) {
                for (int y = 0; y < bitMatrix.getHeight(); y++) {
                    //二维坐标整个区域：画什么颜色
                    image.setRGB(x, y, bitMatrix.get(x, y) ? MatrixToImageConfig.BLACK : MatrixToImageConfig.WHITE);
                }
            }

            //创建画布的缓冲区
            BufferedImage bufferedImage = new BufferedImage(WIDTH_AND_HEIGHT, WIDTH_AND_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR);

            //创建画布
            Graphics2D g2d = bufferedImage.createGraphics();
            //设置背景颜色
            g2d.setBackground(Color.WHITE);
            //开启文字抗锯齿
            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            //绘制二维码
            g2d.drawImage(image, 10, 30, image.getWidth(), image.getHeight(), null);
            //设置画笔颜色
            g2d.setColor(Color.BLACK);
            Font fontChinese = new Font("微软雅黑", Font.PLAIN, 16);
            ///设置二维码文本字体
            g2d.setFont(fontChinese);

            // 绘制文字(文字绘制在二维图图片的上方中间位置)
            g2d.drawString(qrcode, TEXT_X, TEXT_Y);

            //销毁画笔
            g2d.dispose();

            bufferedImage.flush();
            image = bufferedImage;
            return QrCodeInfoDTO.builder().qrCode(qrcode).image(image).build();
        } catch (WriterException e) {
            e.printStackTrace();
            // 抛出异常了
            return null;
        }
    }

    /**
     * 绘制二维码并返回图片流
     *
     * @param qrcode: 二维码值
     * @date 2022/4/8 14:44
     * @author YD
     */
    public static QrCodeInfoDTO createQrCode2(String qrcode, String deviceCode, String deviceName) {
        try {
            //设置对象并生成二维码
            BitMatrix bitMatrix = new MultiFormatWriter().encode(qrcode, BarcodeFormat.QR_CODE, WIDTH_AND_HEIGHT, WIDTH_AND_HEIGHT, HINTS);
            //创建二维码图片缓冲区
            BufferedImage image = new BufferedImage(WIDTH_AND_HEIGHT, WIDTH_AND_HEIGHT, BufferedImage.TYPE_INT_RGB);
            //生成二维码数组
            for (int x = 0; x < bitMatrix.getWidth(); x++) {
                for (int y = 0; y < bitMatrix.getHeight(); y++) {
                    //二维坐标整个区域：画什么颜色
                    image.setRGB(x, y, bitMatrix.get(x, y) ? MatrixToImageConfig.BLACK : MatrixToImageConfig.WHITE);
                }
            }

            //创建画布的缓冲区
            BufferedImage bufferedImage = new BufferedImage(WIDTH_AND_HEIGHT, WIDTH_AND_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR);

            //创建画布
            Graphics2D g2d = bufferedImage.createGraphics();
            //设置背景颜色
            g2d.setBackground(Color.WHITE);
            //开启文字抗锯齿
            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            //绘制二维码
            g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
            //设置画笔颜色
            g2d.setColor(Color.BLACK);
//            Font fontChinese = new Font("微软雅黑", Font.PLAIN, 16);
            Font fontChinese = new Font("宋体", Font.PLAIN, 16);
//            Font fontChinese = new Font(UIManager.getSystemLookAndFeelClassName(), Font.PLAIN, 16);
            // centos7 安装宋体方法，将windows字体目录C:\Windows\Fonts下的simsun.ttc字体文件复制到/usr/share/fonts/目录下，在center服务器执行命令fc-cache -fv，查看命令fc-list

            ///设置二维码文本字体
            g2d.setFont(fontChinese);

            // 绘制文字(文字绘制在二维图图片的上方中间位置)
            g2d.drawString(deviceCode, (WIDTH_AND_HEIGHT - g2d.getFontMetrics().stringWidth(deviceCode)) / 2, 40);
            // 绘制文字(文字绘制在二维图图片的下方中间位置)
//            String deviceNameUtf8 = new String(deviceName.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            g2d.drawString(deviceName, (WIDTH_AND_HEIGHT - g2d.getFontMetrics().stringWidth(deviceName)) / 2, 380);

            //销毁画笔
            g2d.dispose();

            bufferedImage.flush();
            image = bufferedImage;
            return QrCodeInfoDTO.builder().qrCode(qrcode).image(image).build();
        } catch (WriterException e) {
            e.printStackTrace();
            // 抛出异常了
            return null;
        }
    }

    /**
     * 将BufferedImage转换为InputStream
     *
     * @param image: 图片流
     * @date 2022/4/8 15:29
     * @author YD
     */
    public static InputStream bufferedImageToInputStream(BufferedImage image) throws IOException {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(image, "png", os);
        try (InputStream input = new ByteArrayInputStream(os.toByteArray())) {
            return input;
        }
    }

    /**
     * 把生成的二维码打进压缩包并下载
     *
     * @param qrCodeInfos: 二维码信息和流的集合
     * @param batchId      批次号
     * @date 2022/4/8 15:26
     * @author YD
     */
    public static void compressQrCodeToZip(List<QrCodeInfoDTO> qrCodeInfos, Long batchId, HttpServletResponse httpServletResponse) {
        try {
            //重置HttpServletResponse防止乱码
            httpServletResponse.reset();
            ZipOutputStream zos = new ZipOutputStream(httpServletResponse.getOutputStream());
            //文件的名称
            String downloadFilename = batchId + "二维码压缩包.zip";
            //转换中文否则可能会产生乱码
            downloadFilename = URLEncoder.encode(downloadFilename, StandardCharsets.UTF_8);
            // 指明response的返回对象是文件流
            httpServletResponse.setContentType("application/octet-stream; charset=UTF-8");
            //设置下载格式和名称
            httpServletResponse.setHeader("Content-Disposition", "attachment;filename=" + downloadFilename);
            //添加二维码进zip压缩包
            qrCodeInfos.forEach(
                qrCodeInfo -> {
                    try {
                        byte[] buf = new byte[8192];
                        int len;
                        //添加二维码进zip
                        ZipEntry entry = new ZipEntry(qrCodeInfo.getQrCode() + ".png");
                        zos.putNextEntry(entry);
                        InputStream inputStream = bufferedImageToInputStream(qrCodeInfo.getImage());
                        //输出压缩包
                        while ((len = inputStream.read(buf)) > 0) {
                            zos.write(buf, 0, len);
                        }
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            );
            zos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 下载单个二维码
     *
     * @param qrCodeInfo:          二维码值和流信息
     * @param httpServletResponse: http响应
     * @date 2022/4/8 15:37
     * @author YD
     */
    public static void singleQrCode(QrCodeInfoDTO qrCodeInfo, HttpServletResponse httpServletResponse) {
        if (ObjectUtil.isNotNull(qrCodeInfo)) {
            try {
                //重置HttpServletResponse防止乱码
                httpServletResponse.reset();
                //文件的名称
                String downloadFilename = qrCodeInfo.getQrCode() + ".png";
                //转换中文否则可能会产生乱码
                downloadFilename = URLEncoder.encode(downloadFilename, StandardCharsets.UTF_8);
                // 指明response的返回对象是文件流
                httpServletResponse.setContentType("application/octet-stream; charset=UTF-8");
                //设置下载格式和名称
                httpServletResponse.setHeader("Content-Disposition", "attachment;filename=" + downloadFilename);
                //输出二维码到前端
                ImageIO.write(qrCodeInfo.getImage(), "png", httpServletResponse.getOutputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
